using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using MIMPGameLibrary;

namespace MIMP
{
    /// <summary>
    /// The main Game object for the MIMP game.
    /// </summary>
    public class MIMPGame : Microsoft.Xna.Framework.Game
    {
        public const int WINDOW_WIDTH = 1024;
        public const int WIDOW_HEIGHT = 768;
        public const string CONTENT_DIR = "Sprites\\";
        public const string MONSTER_SPRITES_DIR = CONTENT_DIR + "Monsters\\";
        public const string CONROL_PANEL_SPRITES_DIR = CONTENT_DIR + "Control Panel\\";
        public const string GAMEPLAY_SCREEN_SPRITES_DIR = CONTENT_DIR + "Main Screen\\";
        public const string MONSTER_XML_DIR = ".\\MonsterDefinitions\\";
        public const string MAPS_DIR = ".\\Maps\\";
        public const string SAVED_GAMES_DIR = ".\\Saved Games\\";

        GraphicsDeviceManager graphics;

        /// <summary>
        /// A GameState that controls the actual gameplay.
        /// </summary>
        GameState gameState;
        ScreenManager screenManager;

        public ScreenManager ScreenManager
        {
            get { return screenManager; }
        }

        IGameStateService gsService;

        public MIMPGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            gameState = new GameState(0, 0, 0);

            //Logger.Write("MIMPGame instantiated.", "MIMPLog");
            GameStateComponent gsComponent = new GameStateComponent(this, gameState);
            GameplayScreen screen = new GameplayScreen(this);
                        
            Services.AddService(typeof(IGameStateService), gsComponent);
            Services.AddService(typeof(IGameplayScreenService), screen);

            screenManager = new ScreenManager(this);
            Components.Add(screenManager);
            List<GameScreen> screens = new List<GameScreen>();
            screenManager.AddScreen(new MainMenuScreen(false));

            Components.Add(gsComponent);
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            graphics.PreferredBackBufferWidth = MIMPGame.WINDOW_WIDTH;
            graphics.PreferredBackBufferHeight = MIMPGame.WIDOW_HEIGHT;

            //Set graphics.IsFullScreen to true to have the window take up the whole screen. 
            //NOTE: do not do this while debugging as it makes switching back and forth from 
            //the game to Visual Studio impossible.
            graphics.IsFullScreen = false;

            graphics.ApplyChanges();

            this.IsMouseVisible = true;

            gsService = (IGameStateService)Services.GetService(typeof(IGameStateService));
            gsService.LoadGame += new EventHandler(gsService_LoadGame);
            //Logger.Write("MIMPGame intialized.", "MIMPLog");
            base.Initialize();
        }

        public void gsService_LoadGame(object sender, EventArgs e)
        {
            LoadGameArgs lga = (LoadGameArgs)e;
            gameState = lga.StateToLoad;
            
            Components.RemoveAt(Components.Count - 1);

            Services.RemoveService(typeof(IGameStateService));
            Services.RemoveService(typeof(IGameplayScreenService));

            GameStateComponent gsComponent = new GameStateComponent(this, gameState);
            GameplayScreen screen = new GameplayScreen(this);
                        
            Services.AddService(typeof(IGameStateService), gsComponent);
            Services.AddService(typeof(IGameplayScreenService), screen);
                        
            Components.Add(gsComponent);
            
            gsService = (IGameStateService)Services.GetService(typeof(IGameStateService));
            gsService.LoadGame += new EventHandler(gsService_LoadGame);

            screenManager.AddScreen(screen);
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {

        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            //Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.DarkSlateGray);

            base.Draw(gameTime);
        }
    }
}